﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;

namespace IchiaTester
{
    /// <summary>
    /// 串口配置页
    /// </summary>
    public partial class SerialPortConfigForm : Form
    {
        /// <summary>
        /// 所有的串口配置项
        /// </summary>
        public List<SerialPortConfig> AllSerialPortConfig { get; private set; } = new List<SerialPortConfig>();

        public static Dictionary<string, bool> SyncStateDict { get; private set; } = new Dictionary<string, bool>();
        public static Dictionary<string, string> SyncFrameDict { get; private set; } = new Dictionary<string, string>();

        public static Dictionary<string, int> DefaultBufferSizeDict { get; private set; } = new Dictionary<string, int>();

        /// <summary>
        /// 临时串口配置项
        /// </summary>
        public SerialPortConfig tempSerialPortConfig { get; private set; } = new SerialPortConfig();

        private MainForm mainForm;


        /// <summary>
        /// 串口配置项结构体
        /// </summary>
        public struct SerialPortConfig
        {
            public int PortID; // 串口配置项Id
            public string PortName; // 端口号
            public int BaudRate; // 波特率
            public int DataBits; // 数据位
            public string Parity; // 校验位
            public string StopBits; // 停止位
            public int BufferSize; // 内存大小
            public bool SyncState; // 同步状态
            public string SyncFrame; // 同步框架
            public string CRCCheck; // CRC校验
        }

        /// <summary>
        /// 持久化到本地磁盘的串口配置文件名 .cfg后缀
        /// </summary>
        private const string FILE_NAME = "SerialPortConfig.cfg";

        /// <summary>
        /// 串口配置文件数据长度
        /// </summary>
        public const int CFG_DATA_LEN = 10;

        /**
         * 串口配置文件每行根据 , 分割成数组后的索引对应的含义
         */
        public const int POS_PORT_ID = 0;
        public const int POS_PORT_NAME = 1;
        public const int POS_BAUD_RATE = 2;
        public const int POS_DATA_BITS = 3;
        public const int POS_PARITY = 4;
        public const int POS_STOP_BITS = 5;
        public const int POS_BUFFER_SIZE = 6;
        public const int POS_SYNC_STATE = 7;
        public const int POS_SYNC_FRAME = 8;
        public const int POS_CRC_CHECK = 9;
        private static string filepath;
        public static bool IsEdit = false;
        public static bool IsPLC = false;
        public static int SelectedPortID = 0;

        public SerialPortConfigForm(MainForm form)
        {
            mainForm = form;

            InitializeComponent();
        }

        /// <summary>
        /// 页面加载之前执行,主要用于初始化页面数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SerialPortConfigForm_Load(object sender, EventArgs e)
        {
            filepath = Application.StartupPath + "\\" + FILE_NAME;
            MainForm.InfoLogAppend($"Try to load SerialPortConfig.cfg from: {filepath}...... ",
                MainForm.SystemState.FileLoading);
            try
            {
                string[] fileLines = File.ReadAllLines(filepath);
                if (fileLines.Length != 0)
                {
                    foreach (string line in fileLines)
                    {
                        string[] items = line.Split(',');
                        if (items.Length == CFG_DATA_LEN)
                        {
                            SerialPortConfig config = new SerialPortConfig
                            {
                                PortID = int.Parse((items[POS_PORT_ID]).Trim()),
                                PortName = items[POS_PORT_NAME].Trim(),
                                BaudRate = int.Parse((items[POS_BAUD_RATE]).Trim()),
                                DataBits = 8,
                                Parity = "None",
                                StopBits = "One",
                                BufferSize = int.Parse((items[POS_BUFFER_SIZE]).Trim()),
                                SyncState = bool.Parse(items[POS_SYNC_STATE].Trim()),
                                SyncFrame = items[POS_SYNC_FRAME].Trim(),
                                CRCCheck = items[POS_CRC_CHECK].Trim()
                            };
                            AllSerialPortConfig.Add(config);
                        }
                    }

                    MainForm.InfoLogAppend($"Successfully loaded SerialPortConfig.cfg from: {filepath}...... ",
                        MainForm.SystemState.LoadFileSuccess);
                    RefreshListView();
                }
                else
                {
                    listViewSerialPortConfig.Items.Clear();
                    MainForm.WarnLogAppend("SerialPortConfig.cfg is empty, set list view to empty!",
                        MainForm.SystemState.WarningHandling);
                }
            }
            catch (DirectoryNotFoundException ex)
            {
                MainForm.ErrorLogAppend(
                    $"SerialPortConfig.cfg directory not found: {filepath}, set list view to empty!",
                    ex.Message + ex.StackTrace, MainForm.SystemState.ErrorHandling);
                MessageBox.Show("錯誤的設定檔路徑: " + Path.GetDirectoryName(filepath) + "\n" + ex.Message, "Error",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                listViewSerialPortConfig.Items.Clear();
            }
            catch (FileNotFoundException ex)
            {
                MainForm.ErrorLogAppend($"SerialPortConfig.cfg not found: {filepath}, set list view to empty!",
                    ex.Message + ex.StackTrace, MainForm.SystemState.ErrorHandling);
                MessageBox.Show("找不到設定檔!" + "\n" + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                listViewSerialPortConfig.Items.Clear();
            }
            catch (Exception ex)
            {
                MainForm.ErrorLogAppend(
                    $"Error occurred when loading SerialPortConfig.cfg: {filepath}, set list view to empty!",
                    ex.Message + ex.StackTrace, MainForm.SystemState.ErrorHandling);
                MessageBox.Show("讀取設定檔發生錯誤: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                listViewSerialPortConfig.Items.Clear();
            }
        }

        /// <summary>
        /// 点击"关闭"按钮,触发事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// <summary>
        /// 点击"确定"按钮,触发事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOK_Click(object sender, EventArgs e)
        {
            MainForm.InfoLogAppend("Try to save SerialPortConfig.cfg......", MainForm.SystemState.FileSaving);
            try
            {
                // 写入文件流
                using (StreamWriter sw = new StreamWriter(filepath))
                {
                    for (int i = 0; i < AllSerialPortConfig.Count; i++)
                    {
                        var config = AllSerialPortConfig[i];
                        string line = string.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9}",
                            config.PortID,
                            config.PortName,
                            config.BaudRate,
                            "8",
                            "None",
                            "One",
                            config.BufferSize,
                            config.SyncState,
                            config.SyncFrame,
                            config.CRCCheck);
                        sw.WriteLine(line);
                    }
                }

                MainForm.InfoLogAppend($"Successfully saved SerialPortConfig.cfg to: {filepath}",
                    MainForm.SystemState.SaveFileSuccess);
                this.DialogResult = DialogResult.OK;
            }
            catch (Exception ex)
            {
                MainForm.ErrorLogAppend($"Error occurred when saving SerialPortConfig.cfg to: {filepath}",
                    ex.Message + ex.StackTrace, MainForm.SystemState.ErrorHandling);
                MessageBox.Show("儲存失敗：" + ex.Message);
            }
        }

        /// <summary>
        /// 点击"新增"按钮,触发事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnAdd_Click(object sender, EventArgs e)
        {
            IsEdit = false;
            SerialPortItem serialPortItem = new SerialPortItem(this);
            listViewSerialPortConfig.Items.Clear();
            if (serialPortItem.ShowDialog() == DialogResult.OK)
            {
                // 串口配置项页中的temp数据赋值给串口配置页中的临时串口配置
                this.tempSerialPortConfig = serialPortItem.tempSerialPortConfig;
                // 所有的串口配置加上临时串口配置
                AllSerialPortConfig.Add(this.tempSerialPortConfig);
                RefreshListView();
            }
        }

        /// <summary>
        /// 点击"编辑"按钮,触发事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnEdit_Click(object sender, EventArgs e)
        {
            if (listViewSerialPortConfig.SelectedItems.Count == 0)
            {
                MessageBox.Show("請選擇要編輯的項目");
                IsEdit = false;
            }
            else if (listViewSerialPortConfig.SelectedItems.Count == 1)
            {
                SerialPortItem serialPortItem = new SerialPortItem(this);
                IsEdit = true;
                ListViewItem selectedItem = listViewSerialPortConfig.SelectedItems[0];
                SelectedPortID = int.Parse(selectedItem.SubItems[POS_PORT_ID].Text);
                this.tempSerialPortConfig = AllSerialPortConfig[SelectedPortID];
                serialPortItem.tempSerialPortConfig = this.tempSerialPortConfig;
                if (serialPortItem.ShowDialog() == DialogResult.OK)
                {
                    this.tempSerialPortConfig = serialPortItem.tempSerialPortConfig;
                    AllSerialPortConfig[SelectedPortID] = this.tempSerialPortConfig;
                    RefreshListView();
                    IsEdit = false;
                }
            }
        }

        /// <summary>
        /// 点击"删除"按钮,触发事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnDelete_Click(object sender, EventArgs e)
        {
            if (listViewSerialPortConfig.SelectedItems.Count > 0)
            {
                ListViewItem selectedItem = listViewSerialPortConfig.SelectedItems[0];
                int id = int.Parse(selectedItem.SubItems[POS_PORT_ID].Text);
                this.AllSerialPortConfig.RemoveAt(id);
                UpdatePortId();
                RefreshListView();
            }
            else
            {
                MessageBox.Show("請選擇要刪除的測項");
            }
        }

        /// <summary>
        /// 点击"上移"按钮,触发事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnMoveUp_Click(object sender, EventArgs e)
        {
            if (listViewSerialPortConfig.SelectedItems.Count > 0 && listViewSerialPortConfig.SelectedItems[0].Index > 0)
            {
                ListViewItem selectedItem = listViewSerialPortConfig.SelectedItems[0];
                int id = int.Parse(selectedItem.SubItems[POS_PORT_ID].Text);
                this.tempSerialPortConfig = AllSerialPortConfig[id];
                this.AllSerialPortConfig.RemoveAt(id);
                id--;
                this.AllSerialPortConfig.Insert(id, this.tempSerialPortConfig);
                UpdatePortId();
                RefreshListView();
            }
        }

        /// <summary>
        /// 点击"下移"按钮,触发事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnMoveDown_Click(object sender, EventArgs e)
        {
            ListViewItem selectedItem = listViewSerialPortConfig.SelectedItems[0];
            int id = int.Parse(selectedItem.SubItems[POS_PORT_ID].Text);
            this.tempSerialPortConfig = AllSerialPortConfig[id];
            this.AllSerialPortConfig.RemoveAt(id);
            id++;
            this.AllSerialPortConfig.Insert(id, this.tempSerialPortConfig);
            UpdatePortId();
            RefreshListView();
        }

        #region Update and Refresh

        /// <summary>
        /// 更新单条串口配置项的id序号
        /// </summary>
        private void UpdatePortId()
        {
            // 更新单条串口配置项的id序号
            List<SerialPortConfig> update = new List<SerialPortConfig>();
            for (int i = 0; i < AllSerialPortConfig.Count; i++)
            {
                var item = AllSerialPortConfig[i];
                item.PortID = i;
                update.Add(item);
            }

            AllSerialPortConfig = update;
        }

        /// <summary>
        /// 刷新串口配置页面的串口展示ListView
        /// </summary>
        private void RefreshListView()
        {
            try
            {
                MainForm.InfoLogAppend("Try to update serial port config form list view......",
                    MainForm.SystemState.UISetting);
                //Add to ListView
                listViewSerialPortConfig.Items.Clear();
                for (int i = 0; i < AllSerialPortConfig.Count; i++)
                {
                    ListViewItem item = new ListViewItem(AllSerialPortConfig[i].PortID.ToString());
                    item.SubItems.Add(AllSerialPortConfig[i].PortName);
                    item.SubItems.Add(AllSerialPortConfig[i].BaudRate.ToString());
                    item.SubItems.Add("8");
                    item.SubItems.Add("None");
                    item.SubItems.Add("One");
                    item.SubItems.Add(AllSerialPortConfig[i].BufferSize.ToString());
                    item.SubItems.Add(AllSerialPortConfig[i].SyncState.ToString());
                    item.SubItems.Add(AllSerialPortConfig[i].CRCCheck);
                    listViewSerialPortConfig.Items.Add(item);
                }

                MainForm.InfoLogAppend("Successfully update serial port config form list view",
                    MainForm.SystemState.UISetSuccess);
            }
            catch (Exception ex)
            {
                MainForm.ErrorLogAppend("Error occurred when update serial port config form list view",
                    ex.Message + ex.StackTrace, MainForm.SystemState.ErrorHandling);
            }
        }
        #endregion
    }
}